home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / DIST / debugnub / RDTMain.c < prev    next >
C/C++ Source or Header  |  1991-06-16  |  31KB  |  1,341 lines

  1. /* begincopyright
  2.   Copyright (c) 1988 Xerox Corporation. All rights reserved.
  3.   Use and copying of this software and preparation of derivative works based
  4.   upon this software are permitted. Any distribution of this software or
  5.   derivative works must comply with all applicable United States export
  6.   control laws. This software is made available AS IS, and Xerox Corporation
  7.   makes no warranty about the software, its performance or its conformity to
  8.   any specification. Any person obtaining a copy of this software is requested
  9.   to send their name and post office or electronic mail address to:
  10.     PCR Coordinator
  11.     Xerox PARC
  12.     3333 Coyote Hill Rd.
  13.     Palo Alto, CA 94304
  14.   endcopyright */
  15.  
  16.  
  17. /*
  18.  * RDTMain.c
  19.  *
  20.  * Demers, April 25, 1990 4:22:10 pm PDT
  21.  * Udagawa, September 20, 1989 3:40:21 pm PDT
  22.  * CHauser, September 19, 1989 4:54:44 pm PDT
  23.  *
  24.  */
  25.  
  26. #include "xr/BasicTypes.h"
  27. #include "xr/Threads.h"
  28. #include "xr/ThreadsBackdoor.h"
  29. #include "xr/Errno.h"
  30. #include "xr/CirioNubTypes.h"
  31. #include "xr/RDTProcs.h"
  32.  
  33. #include <sgtty.h>
  34. #include <sys/signal.h>
  35. #include <sys/file.h>
  36.  
  37. #include <sys/types.h>
  38. #include <sys/ipc.h>
  39. #include <sys/sem.h>
  40. #include <sys/time.h>
  41. #include <fcntl.h>
  42. #include <ctype.h>
  43.  
  44. /*
  45.  * misc parameters
  46.  */
  47.  
  48. /*
  49.  * global state
  50.  */
  51.  
  52. static char *RDT_debuggeeName = NIL;
  53. static unsigned RDT_debuggeePort = 0;
  54. static unsigned RDT_debuggeeProtocolVersion = 0;
  55. static bool RDT_connected = FALSE;
  56.  
  57. static int RDT_examinee = -1;
  58.  
  59. static void
  60. RDT_SetDebuggeeName(name)
  61.     char *name;
  62. {
  63.     if( RDT_debuggeeName != NIL ) {
  64.         (void) free(RDT_debuggeeName);
  65.         RDT_debuggeeName = NIL;
  66.     }
  67.     if( name != NIL ) {
  68.         RDT_debuggeeName = (char *) malloc(1+strlen(name));
  69.         (void) strcpy(RDT_debuggeeName, name);
  70.     }
  71. }
  72.  
  73. /*
  74.  * UNIX signal handlers ...
  75.  */
  76.  
  77. static int RDT_numSIGINTs = 0;
  78.  
  79.  
  80. static int
  81. RDT_OnSIGINT ()
  82. {
  83.     RDT_numSIGINTs += 1;
  84.     return 0;
  85. }
  86.  
  87. static int
  88. RDT_OnSIGALRM ()
  89. {
  90.     return 0;
  91. }
  92.  
  93. static void
  94. RDT_InstallHandler (signal, handler)
  95.     int signal;
  96.     void (*handler)();
  97. {
  98.     struct sigvec vec;
  99.  
  100.     vec.sv_mask = 0;
  101.     vec.sv_flags = SV_INTERRUPT;    /* force read to be interrupted */
  102.     vec.sv_handler = handler;
  103.     (void) sigvec(signal, &vec, NIL);
  104. }
  105.  
  106.  
  107. /*
  108.  * Command parsing stuff
  109.  */
  110.  
  111. #define RDT_INCODE_ERR    (-1)
  112. #define RDT_INCODE_INT    (-2)
  113.  
  114. #define RDT_STDIN    0
  115. #define RDT_STDOUT    1
  116.  
  117. #define CMD_BUF_LEN    256
  118. #define RDT_MAX_ARGS    20
  119.  
  120. static char RDT_cmdBuf[CMD_BUF_LEN];
  121. static char *RDT_cmdPtr = &(RDT_cmdBuf[0]);
  122. #define RDT_cmdLim (&(RDT_cmdBuf[CMD_BUF_LEN-1]))
  123.  
  124. static char *RDT_cmd = NIL;
  125. static int RDT_argc = 0;
  126. static char *(RDT_argv[RDT_MAX_ARGS]);
  127.  
  128. static void
  129. RDT_DiscardInput ()
  130. {
  131.     int which = FREAD;
  132.     (void)ioctl(RDT_STDIN, TIOCFLUSH, &which);
  133.     RDT_cmdBuf[0] = 0;
  134.     RDT_cmdPtr = RDT_cmdBuf;
  135. }
  136.  
  137. static int
  138. RDT_GetChar ()
  139. /*
  140.     Return next input char or DBT_INCODE code.
  141. */
  142. {
  143.     char buf[1];
  144.     int numSIGINTs = RDT_numSIGINTs;
  145.  
  146.     if( read(RDT_STDIN, buf, 1) != 1 )
  147.         return( (errno == EINTR) ? RDT_INCODE_INT : RDT_INCODE_ERR );
  148.     if( numSIGINTs < RDT_numSIGINTs ) return(RDT_INCODE_INT);
  149.     return( buf[0] );
  150. }
  151.  
  152. static int
  153. RDT_GetLine ()
  154. /*
  155.     Read next input line; return its length or RDT_INCODE code.
  156. */
  157. {
  158.     int c;
  159.     char *p;
  160.  
  161.     RDT_cmdPtr = p = RDT_cmdBuf;
  162.     for(;;) {
  163.     if( (c = RDT_GetChar()) < 0 ) break;
  164.     if( p < RDT_cmdLim ) *p++ = c;
  165.     if( c == '\n' ) {
  166.         *p = 0;
  167.         return( p - RDT_cmdBuf );
  168.     }
  169.     }
  170.     return( (c == RDT_INCODE_INT) ? RDT_INCODE_INT : RDT_INCODE_ERR );
  171. }
  172.  
  173. static bool
  174. RDT_IsWhite(c)
  175.     char c;
  176. /*
  177.     Return TRUE iff next char is white space.
  178. */
  179. {
  180.     switch(c) {
  181.       case ' ':
  182.       case '\n':
  183.       case '\r':
  184.       case '\t':
  185.       case 0:
  186.         return(TRUE);
  187.       default:
  188.         return(FALSE);
  189.     }
  190. }
  191.  
  192. static char *
  193. RDT_GetToken ()
  194. /*
  195.     Isolate next token, return pointer to it or NIL.
  196. */
  197. {
  198.     char *p;
  199.     char *result;
  200.     char c;
  201.  
  202.     p = RDT_cmdPtr;
  203.     for(;;) {
  204.         c = *p;
  205.         if( (c == 0) || (c == '\n') ) return( NIL );
  206.     if( !RDT_IsWhite(c) ) break;
  207.     p++;
  208.     }
  209.     result = p;
  210.     for(;;) {
  211.         c = *p;
  212.         if( c == 0 ) break;
  213.         if( RDT_IsWhite(c) || (c == '\n') ) { *p++ = 0; break; }
  214.     p++;
  215.     }
  216.     RDT_cmdPtr = p;
  217.     return( result );
  218. }
  219.  
  220.  
  221. static int
  222. RDT_WaitForCmd ()
  223. {
  224.     int ans;
  225.  
  226.     RDT_cmd = NIL;
  227.     RDT_argc = 0;
  228.     RDT_Msg("(rdt): ");
  229.     RDT_DiscardInput();
  230.     ans = RDT_GetLine();
  231.     switch( ans ) {
  232.       case RDT_INCODE_INT:
  233.       case RDT_INCODE_ERR:
  234.         return ans;
  235.       default:
  236.         ;
  237.     }
  238.  
  239.     if( (RDT_cmd = RDT_GetToken()) == NIL ) return 0;
  240.  
  241.     for(;;) {
  242.         char *token;
  243.     if( (token = RDT_GetToken()) == NIL ) return 0;
  244.     if( RDT_argc < RDT_MAX_ARGS ) {
  245.         RDT_argv[RDT_argc] = token;
  246.         RDT_argc += 1;
  247.     }
  248.     }
  249.     /*NOTREACHED*/
  250. }
  251.  
  252.  
  253.  
  254. typedef
  255. #   define MATCH_NONE    0
  256. #   define MATCH_HELP    1
  257. #   define MATCH_INVOKE    2
  258. int RDT_CmdMatchResult;
  259.  
  260.  
  261. static bool
  262. RDT_MatchInner(input, fullName, len)
  263.     char *input;
  264.     char *fullName;
  265.     int len;
  266. {
  267.     int i;
  268.  
  269.     for( i = 0; ; i++ ) {
  270.         char c = input[i];
  271.         if( c == 0 ) return( i >= len );
  272.         if( c != fullName[i] ) return( FALSE );
  273.     }
  274. }
  275.  
  276.  
  277. static RDT_CmdMatchResult
  278. RDT_CmdMatch(fullName, len)
  279.     char *fullName;
  280.     int len;
  281. {
  282.     if( RDT_MatchInner(RDT_cmd, fullName, len) ) return( MATCH_INVOKE );
  283.     if( RDT_MatchInner(RDT_cmd, "?", 1 )
  284.             || RDT_MatchInner(RDT_cmd, "help", 4 ) ) {
  285.         if( RDT_argc < 1 ) return( MATCH_HELP );
  286.         if( RDT_MatchInner(RDT_argv[0], fullName, len) ) return( MATCH_HELP );
  287.     return( MATCH_NONE );
  288.     }
  289.     return( MATCH_NONE );
  290. }
  291.         
  292.  
  293. static bool
  294. RDT_Confirm(msg)
  295.     char *msg;
  296. {
  297.     bool ans;
  298.     int c;
  299.  
  300.     for(;;) {
  301.         RDT_Msg("%s (y|n): ", msg);
  302.     RDT_DiscardInput();
  303.     switch(c = RDT_GetChar()) {
  304.       case 'y':
  305.       case 'Y':
  306.         ans = TRUE;
  307.         goto out;
  308.       case 'n':
  309.       case 'N':
  310.         ans = FALSE;
  311.         goto out;
  312.       case RDT_INCODE_ERR:
  313.         ans = TRUE; /* sigh */
  314.         goto out;
  315.       case RDT_INCODE_INT:
  316.       default:
  317.         ;
  318.     }
  319.     }
  320.   out:
  321.     while( ((c = RDT_GetChar()) >= 0)  && (c != '\n') ) ;
  322.     return( ans );
  323. }
  324.  
  325.  
  326. /*
  327.  * Command primitives ...
  328.  */
  329.  
  330. static int
  331. RDT_DoKillWorld ()
  332. {
  333.     int i, ans;
  334.  
  335.     if( !RDT_Confirm("Kill world? ") ) return 1;
  336.     RDT_Msg("Good-bye.\n");
  337.     ans = RDT_KillWorld();
  338.     RDT_connected = FALSE;
  339.     return ans;
  340. }
  341.  
  342.  
  343. static int
  344. RDT_DoSetDBStat (stat)
  345.     int stat;
  346. {
  347.     int ans;
  348.  
  349.     ans = RDT_SetDBStat( stat, 6000 );
  350.     if( ans > 0 ) {
  351.         RDT_Msg("Can't set debuggee state to %d\n", stat);
  352.         ans = 0;
  353.     }
  354.     return ans;
  355. }
  356.  
  357.  
  358.  
  359. static int
  360. RDT_DoStop ()
  361. {
  362.     int ans;
  363.  
  364.     if( (ans = RDT_DoSetDBStat(XR_DBSTAT_STOP)) < 0 ) {
  365.         RDT_Msg("Can't stop debuggee.\n");
  366.     }
  367.     return ans;
  368. }
  369.  
  370.  
  371. static int
  372. RDT_GetTIDArg (i, dataPtr)
  373.     unsigned i;
  374.     CirioNubThreadData *dataPtr;
  375. {
  376.     int index, ans;
  377.  
  378.     if( i >= RDT_argc ) {
  379.     RDT_Msg("ThreadID?\n");
  380.     return( 1 );
  381.     }
  382.     index = atoi(RDT_argv[i]);
  383.     ans = RDT_GetThread(index, dataPtr);
  384.     if( ans < 0 ) {
  385.         RDT_Msg("Can't lookup thread %s.\n", RDT_argv[i]);
  386.     } else if( ans > 0 ) {
  387.         RDT_Msg("Thread %s nonexistent.\n", RDT_argv[i]);
  388.     } else if( !RDT_ThreadIsActive(*dataPtr) ) {
  389.         RDT_Msg("Thread %d inactive.\n", (*dataPtr)->cntd_index);
  390.         RDT_FreeThreadData(dataPtr);
  391.         ans = 1;
  392.     }
  393.     return ans;
  394. }
  395.  
  396.  
  397.  
  398. static int
  399. RDT_DoGetState()
  400. {
  401.     int index = 999999;
  402.     int dbStat = 999999;
  403.     int ans;
  404.  
  405.     ans = RDT_GetDBStat( /*timeout*/ 0, &index, &dbStat );
  406.     if( ans >= 0 ) {
  407.         if( index >= 0 ) {
  408.             RDT_Msg("Examining %d.\n", index);
  409.         } else switch(dbStat) {
  410.             case XR_DBSTAT_STOP:
  411.                 RDT_Msg("Stopped.\n");
  412.                 break;
  413.             case XR_DBSTAT_RUN0:
  414.                 RDT_Msg("Running uniprocessor.\n");
  415.                 break;
  416.             case XR_DBSTAT_RUN:
  417.                 RDT_Msg("Running multiprocessor.\n");
  418.                 break;
  419.             default:
  420.                 RDT_Msg("Trying to examine %d.\n", dbStat);
  421.                 break;
  422.         }
  423.         ans = 0;
  424.     }
  425.     return ans;
  426. }
  427.  
  428.  
  429. static int
  430. RDT_DoExamine ()
  431. {
  432.     CirioNubThreadData threadData = NIL;
  433.     int ans;
  434.  
  435.     if( (ans = RDT_DoStop()) < 0 ) goto Out;
  436.     if( (ans = RDT_GetTIDArg(0, &threadData)) == 0 ) {
  437.         RDT_Msg("Examine %d ... ", threadData->cntd_index);
  438.         if( (ans = RDT_DoSetDBStat(threadData->cntd_index)) >= 0 ) {
  439.             RDT_Msg("ok\n");
  440.         } else {
  441.             (void) RDT_DoStop();
  442.         }
  443.         RDT_examinee = threadData->cntd_index;
  444.     }
  445.   Out:
  446.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  447.     return ans;
  448. }
  449.  
  450. static int
  451. RDT_DoFreeze ()
  452. {
  453.     CirioNubThreadData threadData = NIL;
  454.     int ans;
  455.  
  456.     if( (ans = RDT_DoStop()) < 0 ) goto Out;
  457.     if( (ans = RDT_GetTIDArg(0, &threadData)) == 0 ) {
  458.         if( threadData->cntd_dbFrozen ) {
  459.             RDT_Msg("Thread %d already frozen.\n", threadData->cntd_index);
  460.             goto Out;
  461.         }
  462.         RDT_Msg("Freezing %d ... ", threadData->cntd_index);
  463.         ans = RDT_IssueThreadCommand (
  464.                 threadData->cntd_index,
  465.                 TRUE, TRUE,
  466.                 FALSE, 0 );
  467.         RDT_Msg("%s.\n", ((ans == 0) ? "frozen" : "failed") );
  468.     }
  469.   Out:
  470.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  471.     return ans;
  472. }
  473.  
  474.  
  475. static int
  476. RDT_DoAbort ()
  477. {
  478.     CirioNubThreadData threadData = NIL;
  479.     int ans;
  480.  
  481.     if( (ans = RDT_DoStop()) < 0 ) goto Out;
  482.     if( (ans = RDT_GetTIDArg(0, &threadData)) == 0 ) {
  483.         if( threadData->cntd_dbMsg <= 0 ) {
  484.         RDT_Msg("Thread %d not calling debugger.\n",
  485.                 threadData->cntd_index);
  486.         goto Out;
  487.         }
  488.         RDT_Msg("Aborting %d ... ", threadData->cntd_index);
  489.         ans = RDT_IssueThreadCommand (
  490.                 threadData->cntd_index,
  491.                 TRUE, FALSE,
  492.                 TRUE, XR_DB_MSG_ABORT_REPLY );
  493.         RDT_Msg("%s.\n", ((ans == 0) ? "aborted" : "failed") );
  494.     }
  495.   Out:
  496.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  497.     return ans;
  498. }
  499.  
  500.  
  501.  
  502. static int
  503. RDT_DoThaw ()
  504. {
  505.     CirioNubThreadData threadData = NIL;
  506.     int ans;
  507.  
  508.     if( (ans = RDT_DoStop()) < 0 ) goto Out;
  509.     if( (ans = RDT_GetTIDArg(0, &threadData)) == 0 ) {
  510.         RDT_Msg("Thawing %d ... ", threadData->cntd_index);
  511.         ans = RDT_IssueThreadCommand (
  512.                 threadData->cntd_index,
  513.                 TRUE, FALSE, /* clear dbFreeze */
  514.                 XR_DB_MSG_IS_REQUEST(threadData->cntd_dbMsg),
  515.                 XR_DB_MSG_PROCEED_REPLY /* proceed if calling debugger */
  516.                 );
  517.         RDT_Msg("%s.\n", ((ans == 0) ? "thawed" : "failed") );
  518.     }
  519.   Out:
  520.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  521.     return ans;
  522. }
  523.  
  524.  
  525.  
  526. static int
  527. RDT_DoKill ()
  528. {
  529.     CirioNubThreadData threadData = NIL;
  530.     int ans;
  531.  
  532.     if( (ans = RDT_DoStop()) < 0 ) goto Out;
  533.     if( (ans = RDT_GetTIDArg(0, &threadData)) == 0 ) {
  534.         if( !(XR_DB_MSG_IS_REQUEST(threadData->cntd_dbMsg)) ) {
  535.         RDT_Msg("Thread %d not calling debugger.\n",
  536.                 threadData->cntd_index);
  537.         goto Out;
  538.         }
  539.         RDT_Msg("Killing %d ... ", threadData->cntd_index);
  540.         ans = RDT_IssueThreadCommand (
  541.                 threadData->cntd_index,
  542.                 TRUE, TRUE,
  543.                 TRUE, XR_DB_MSG_EXIT_REPLY );
  544.         RDT_Msg("%s.\n", ((ans == 0) ? "r.i.p" : "won't die") );
  545.     }
  546.   Out:
  547.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  548.     return ans;
  549. }
  550.  
  551.  
  552. static bool
  553. RDT_ThreadIsActive(cntd)
  554.     CirioNubThreadData cntd;
  555. {
  556.     if( cntd == NIL ) {
  557.         return FALSE;
  558.     } else switch( cntd->cntd_sStat ) {
  559.         case XR_SSTAT_NONE:
  560.         case XR_SSTAT_FREE:
  561.             return FALSE;
  562.     case XR_SSTAT_READY:
  563.     case XR_SSTAT_RUN:
  564.     case XR_SSTAT_WAIT_ML:
  565.     case XR_SSTAT_WAIT_CV:
  566.         return TRUE;
  567.     default:
  568.         RDT_Msg( "(RDT_ThreadIsActive internal error %d)\n",
  569.                 cntd->cntd_sStat );
  570.         return FALSE;
  571.     }
  572. }
  573.  
  574.  
  575. static void
  576. RDT_PutOneThread (cntd)
  577.     CirioNubThreadData cntd;
  578. {
  579.     static char sstat_chars[] = "?FRRMCH";
  580.  
  581.     if( cntd->cntd_dbMsg != 0 ) RDT_Msg("*[%d]", cntd->cntd_dbMsg);
  582.     RDT_Msg("%d%c", cntd->cntd_index, sstat_chars[cntd->cntd_sStat]);
  583.     RDT_Msg( "%s%s   ",
  584.             ((cntd->cntd_index == RDT_examinee) ? "e" : ""),
  585.             (cntd->cntd_dbFrozen ? "f" : "") );
  586. }
  587.  
  588.  
  589. static int
  590. RDT_DoPutThreads()
  591. {
  592.     int i, ans;
  593.     CirioNubThreadData threadData = NIL;
  594.  
  595.     for( i = 0; ; i++ ) {
  596.         ans = RDT_GetThread(i, &threadData);
  597.         if( ans != 0 ) break;
  598.         if( RDT_ThreadIsActive(threadData) ) RDT_PutOneThread(threadData);
  599.         RDT_FreeThreadData(&threadData);
  600.     }
  601.     RDT_Msg("\n");
  602.   Out:
  603.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  604.     return ans;
  605. }
  606.  
  607.  
  608. #if defined(sparc)
  609.  
  610. static int
  611. RDT_DoGetAndDisplayPrevFrame(spp, fpp, pcp, prolixity)
  612.     XR_Pointer *spp, *fpp, *pcp;
  613.     int prolixity;
  614. {
  615.     int ans;
  616.     XR_Pointer savedRegs[16];
  617.  
  618.     ans = RDT_GetWords32( ((unsigned )(*spp)),
  619.             (sizeof savedRegs), ((unsigned *)(savedRegs)) );
  620.     if( ans != (sizeof savedRegs) ) return (-1);
  621.     if( prolixity > 1 ) {
  622.         XR_Pointer *inReg = &savedRegs[8];
  623.         int i = 0;
  624.         int j;
  625.         while( i < 8 ) {
  626.             for( j = 0; j < 4; j++ ) {
  627.                 RDT_Msg("  i%-2d: %8x", i, *inReg);
  628.                 i += 1;
  629.                 inReg += 1;
  630.             }
  631.             RDT_Msg("\n");
  632.         }
  633.     }
  634.     *pcp = XR_OLD_PC_FROM_FRAME(0, (&(savedRegs[0])) );
  635.     *spp = XR_OLD_SP_FROM_FRAME(0, (&(savedRegs[0])) );
  636.     *fpp = /* XR_OLD_FP_FROM_FRAME(0, (&(savedRegs[0])) ); ??? */ 0;
  637.     return 0;
  638. }
  639.  
  640.  
  641. #else
  642.  
  643. static int
  644. RDT_DoGetPrevFrameAndPC(spp, fpp, pcp)
  645.     XR_Pointer *spp, *fpp, *pcp;
  646. {
  647.     --> fix me for target architecture <--
  648. }
  649.  
  650. #endif
  651.  
  652. static int
  653. RDT_DoDisplayProcName(pc, sp, prolixity)
  654.     XR_Pointer pc;
  655.     XR_Pointer sp;
  656.     int prolixity;
  657. {
  658.     int ans;
  659.     CirioNubPCInfo procInfo = NIL;
  660.  
  661.     ans = RDT_PCtoInfo(pc, &procInfo);
  662.     if( ans == 0 ) {
  663.         RDT_Msg( "%s ", ((procInfo->procName != NIL)
  664.                 ? procInfo->procName : "(no name)" ) );
  665.         RDT_Msg( "(pc 0x%x, ", pc);
  666.         RDT_Msg( "sp 0x%x) ", sp);
  667.         if( prolixity > 0 ) {
  668.             if( procInfo->guessedEmbeddedFileName != NIL ) {
  669.                 RDT_Msg("from embedded file %s ",
  670.                         procInfo->guessedEmbeddedFileName );
  671.             }
  672.             RDT_Msg( "in file %s.\n", ((procInfo->fileName != NIL)
  673.                     ? procInfo->fileName : "(unknown)" ) );
  674.         } else {
  675.             RDT_Msg( "\n");
  676.         }
  677.     } else {
  678.         RDT_Msg("(can't find pc 0x%x).\n", pc);
  679.     }
  680.     if( procInfo != NIL ) RDT_FreePCInfo (&procInfo);
  681.     return ans;
  682. }
  683.  
  684.  
  685. static int
  686. RDT_DoDisplayOneThread(cntd, nf, prolixity)
  687.     CirioNubThreadData cntd;
  688.     int nf;
  689.     int prolixity;
  690. {
  691.     int ans = 0;
  692.     XR_Pointer pc, fp, sp;
  693.     int i;
  694.  
  695.     RDT_PutOneThread(cntd);
  696.     RDT_Msg(" pri = %d", cntd -> cntd_pri);
  697.     RDT_Msg(" stack display:\n");
  698.     pc = cntd->cntd_pc;
  699.     fp = cntd->cntd_fp;
  700.     sp = cntd->cntd_sp;
  701.     for(i = 0; ; i++) {
  702.         if( i == nf ) break;
  703.         if( pc == NIL ) break;
  704.         RDT_Msg("%d.%d: ", cntd->cntd_index, i);
  705.         (void) RDT_DoDisplayProcName(pc, sp, prolixity);
  706.         if( sp == NIL ) break;
  707.         ans = RDT_DoGetAndDisplayPrevFrame(&sp, &fp, &pc, prolixity);
  708.         if( ans != 0 ) break;
  709.     }
  710.     return ans;
  711. }
  712.  
  713. static int
  714. RDT_DoDisplayThreads()
  715. {
  716.     CirioNubThreadData threadData = NIL;
  717.     int i, ans;
  718.     int numFrames = -1;
  719.     int prolixity = 0;
  720.  
  721.     if( (ans = RDT_DoStop()) < 0 ) goto Out;
  722.     if( RDT_argc > 0 ) {
  723.         if( RDT_argc > 1 ) {
  724.             numFrames = atoi(RDT_argv[1]);
  725.             if( RDT_argc > 2 ) {
  726.                 prolixity = atoi(RDT_argv[2]);
  727.             }
  728.         }
  729.         if( (ans = RDT_GetTIDArg(0, &threadData)) == 0 ) {
  730.             if( RDT_ThreadIsActive(threadData) ) {
  731.                 (void)RDT_DoDisplayOneThread(threadData, numFrames, prolixity);
  732.             } else {
  733.                 RDT_Msg("Thread %d inactive.\n", threadData->cntd_index);
  734.             }
  735.         }
  736.     } else {
  737.         for(i = 0; ; i++ ) {
  738.             ans = RDT_GetThread(i, &threadData);
  739.             if( ans != 0 ) break;
  740.             if( RDT_ThreadIsActive(threadData) ) {
  741.                 ans = RDT_DoDisplayOneThread(threadData, numFrames, prolixity);
  742.                 if( ans != 0 ) break;
  743.             }
  744.             RDT_FreeThreadData(&threadData);
  745.         }
  746.     }
  747.   Out:
  748.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  749.     return ans;
  750. }
  751.  
  752.  
  753. static int
  754. RDT_PutStr(str, fd)
  755.     char *str;
  756.     int fd;
  757. {
  758.     int ans, len;
  759.  
  760.     len = strlen(str);
  761.     while( len > 0 ) {
  762.         ans = write(fd, str, len);
  763.         if( ans <= 0 ) return ans;
  764.         str += ans;
  765.         len -= ans;
  766.     }
  767.     return 0;
  768. }
  769.  
  770. static int
  771. RDT_DoSaveProcName(pc, fd)
  772.     XR_Pointer pc;
  773.     int fd;
  774. {
  775.     int ans;
  776.     CirioNubPCInfo procInfo = NIL;
  777.  
  778.     ans = RDT_PCtoInfo(pc, &procInfo);
  779.     if( ans == 0 ) {
  780.         if( procInfo->guessedEmbeddedFileName != NIL )
  781.             ans = RDT_PutStr( procInfo->guessedEmbeddedFileName, fd );
  782.         if( ans == 0 )
  783.             ans = RDT_PutStr( " ", fd );
  784.     }
  785.     if( procInfo != NIL ) RDT_FreePCInfo (&procInfo);
  786.     return ans;
  787. }
  788.  
  789.  
  790. static int
  791. RDT_DoSaveOneThread(cntd, nf, fd)
  792.     CirioNubThreadData cntd;
  793.     int nf;
  794.     int fd;
  795. {
  796.     int ans = 0;
  797.     XR_Pointer pc, fp, sp;
  798.     int i;
  799.  
  800.     pc = cntd->cntd_pc;
  801.     fp = cntd->cntd_fp;
  802.     sp = cntd->cntd_sp;
  803.     for(i = 0; ; i++) {
  804.         if( i == nf ) break;
  805.         if( pc == NIL ) break;
  806.         ans = RDT_DoSaveProcName(pc, fd);
  807.         if( ans != 0 ) break;
  808.         if( sp == NIL ) break;
  809.         ans =RDT_DoGetAndDisplayPrevFrame(&sp, &fp, &pc, /*prolixity=*/ 0);
  810.         if( ans != 0 ) break;
  811.     }
  812.     return ans;
  813. }
  814.  
  815. char *RDT_saveFileName = "DBXObjectNames";
  816.  
  817. static int
  818. RDT_DoSave()
  819. {
  820.     CirioNubThreadData threadData = NIL;
  821.     int i, ans;
  822.     int numFrames = -1;
  823.     int fd = -1;
  824.  
  825.     if( (ans = RDT_DoStop()) < 0 ) goto Out;
  826.     fd = open(RDT_saveFileName, (O_WRONLY|O_CREAT|O_TRUNC), 0666);
  827.     if( fd < 0 ) {
  828.         RDT_Msg("Cannot create %s.\n", RDT_saveFileName);
  829.         ans = 1;
  830.         goto Out;
  831.     }
  832.     ans = RDT_PutStr("modules select ", fd);
  833.     if( ans != 0 ) {
  834.         ans = 1;
  835.         goto Out;
  836.     }
  837.     if( RDT_argc > 0 ) {
  838.         if( RDT_argc > 1 ) {
  839.             numFrames = atoi(RDT_argv[1]);
  840.         }
  841.         if( (ans = RDT_GetTIDArg(0, &threadData)) == 0 ) {
  842.             if( RDT_ThreadIsActive(threadData) ) {
  843.                 (void)RDT_DoSaveOneThread(threadData, numFrames, fd);
  844.             } else {
  845.                 RDT_Msg("Thread %d inactive.\n", threadData->cntd_index);
  846.             }
  847.         }
  848.     } else {
  849.         for(i = 0; ; i++ ) {
  850.             ans = RDT_GetThread(i, &threadData);
  851.             if( ans != 0 ) break;
  852.             if( RDT_ThreadIsActive(threadData) ) {
  853.                 ans = RDT_DoSaveOneThread(threadData, numFrames, fd);
  854.             }
  855.             RDT_FreeThreadData(&threadData);
  856.             if( ans != 0 ) break;
  857.         }
  858.     }
  859.     (void) RDT_PutStr("\n", fd);
  860.  
  861.   Out:
  862.  
  863.     if( fd >= 0 ) (void)close(fd);
  864.     if( threadData != NIL ) RDT_FreeThreadData(&threadData);
  865.     return ans;
  866. }
  867.  
  868.  
  869. static int
  870. RDT_DoGetDebuggeeProtocolVersion(desiredVersion)
  871.     unsigned desiredVersion;
  872. {
  873.     unsigned hisVersion;
  874.     int ans;
  875.  
  876.     ans = RDT_Null(desiredVersion, &hisVersion);
  877.     if( ans == 0 ) {
  878.         if( hisVersion != desiredVersion ) {
  879.             RDT_Msg("Protocol version mismatch.  Wanted %d.  ", desiredVersion);
  880.             ans = -1;
  881.         }
  882.         RDT_Msg("Debuggee protocol version %d.\n", hisVersion);
  883.     }
  884.     return ans;
  885. }
  886.  
  887.  
  888. static int
  889. RDT_DoWPeek()
  890. {
  891.     unsigned addr;
  892.     int i;
  893.     int n = 1;
  894.     unsigned buf[64];
  895.  
  896.     if( RDT_argc < 1 ) return(-1);
  897.     i = strtol(RDT_argv[0], 0, 0);
  898.     if( i == (-1) ) {
  899.         RDT_Msg("Bad address %s\n", RDT_argv[0]);
  900.         return (-1);
  901.     }
  902.     addr = ((unsigned)(i & (~(sizeof(unsigned)-1))));
  903.     if( RDT_argc >= 2 ) {
  904.         n = atoi(RDT_argv[1]);
  905.         if( (n <= 0) || (n > ((sizeof buf)/sizeof(unsigned))) ) {
  906.             RDT_Msg("Bad count %s\n", RDT_argv[1]);
  907.             return (-1);
  908.         }
  909.     }
  910.     i = RDT_GetWords32(addr, n*sizeof(unsigned), buf);
  911.     if( i != (n*sizeof(unsigned)) ) {
  912.         RDT_Msg("can't read debuggee memory, err %d\n", i);
  913.         return (-1);
  914.     }
  915.     for( i = 0; i < n; i++ ) {
  916.         RDT_Msg("  0x%x: 0x%x (%d)\n", addr, buf[i], buf[i]);
  917.         addr += sizeof(unsigned);
  918.     }
  919. }
  920.  
  921.  
  922. static int
  923. RDT_DoBPeek()
  924. {
  925.     unsigned addr;
  926.     int i;
  927.     int n = 1;
  928.     char buf[64];
  929.  
  930.     if( RDT_argc < 1 ) return(-1);
  931.     i = strtol(RDT_argv[0], 0, 0);
  932.     if( i == (-1) ) {
  933.         RDT_Msg("Bad address %s\n", RDT_argv[0]);
  934.         return (-1);
  935.     }
  936.     addr = ((unsigned)(i));
  937.     if( RDT_argc >= 2 ) {
  938.         n = atoi(RDT_argv[1]);
  939.         if( (n <= 0) || (n > ((sizeof buf)/sizeof(char))) ) {
  940.             RDT_Msg("Bad count %s\n", RDT_argv[1]);
  941.             return (-1);
  942.         }
  943.     }
  944.     i = RDT_GetBytes(addr, n*sizeof(char), buf);
  945.     if( i != (n*sizeof(char)) ) {
  946.         RDT_Msg("can't read debuggee memory, err %d\n", i);
  947.         return (-1);
  948.     }
  949.     for( i = 0; i < n; i++ ) {
  950.         int c = toascii(buf[i]);
  951.         if( !(isgraph(c)) ) c = '?';
  952.         RDT_Msg("  0x%x: 0x%x ('%c')\n", addr, buf[i], c);
  953.         addr += sizeof(char);
  954.     }
  955. }
  956.  
  957.  
  958. static int
  959. RDT_DoWPoke()
  960. {
  961.     int i, x;
  962.     unsigned addr;
  963.     unsigned buf[1];
  964.  
  965.     if( RDT_argc < 1 ) return(-1);
  966.     x = strtol(RDT_argv[0], 0, 0);
  967.     if( x == (-1) ) {
  968.         RDT_Msg("Bad address %s\n", RDT_argv[0]);
  969.         return (-1);
  970.     }
  971.     addr = ((unsigned)(x & (~(sizeof(unsigned)-1))));
  972.     for( i = 1; i < RDT_argc; i++ ) {
  973.         buf[0] = strtol(RDT_argv[i], 0, 0);
  974.         x = RDT_PutWords32(addr, (sizeof buf), buf);
  975.         if( x != (sizeof buf) ) {
  976.             RDT_Msg("can't write debuggee memory at 0x%x, err %d\n", addr, x);
  977.             return (-1);
  978.         }
  979.         addr += (sizeof buf);
  980.     }
  981. }
  982.  
  983.  
  984. static int
  985. RDT_DoBPoke()
  986. {
  987.     int i, x;
  988.     unsigned addr;
  989.     char buf[1];
  990.  
  991.     if( RDT_argc < 1 ) return(-1);
  992.     x = strtol(RDT_argv[0], 0, 0);
  993.     if( x == (-1) ) {
  994.         RDT_Msg("Bad address %s\n", RDT_argv[0]);
  995.         return (-1);
  996.     }
  997.     addr = ((unsigned)(x & (~(sizeof(char)-1))));
  998.     for( i = 1; i < RDT_argc; i++ ) {
  999.         buf[0] = strtol(RDT_argv[i], 0, 0);
  1000.         x = RDT_PutBytes(addr, (sizeof buf), buf);
  1001.         if( x != (sizeof buf) ) {
  1002.             RDT_Msg("can't write debuggee memory at 0x%x, err %d\n", addr, i);
  1003.             return (-1);
  1004.         }
  1005.         addr += (sizeof buf);
  1006.     }
  1007. }
  1008.  
  1009.  
  1010. static void
  1011. RDT_DoWithConnection( proc, arg )
  1012.     int (*proc)(/* int arg */);
  1013.     int arg;
  1014. {
  1015.     int ans;
  1016.  
  1017.     if( !RDT_connected ) {
  1018.         RDT_Msg("no connection.\n");
  1019.         return;
  1020.     }
  1021.     ans = (*proc)(arg);
  1022.     if( ans < 0 ) {
  1023.         (void)RDT_Disconnect(TRUE);
  1024.         RDT_connected = FALSE;
  1025.         RDT_Msg("connection broken.\n");
  1026.     }
  1027. }
  1028.  
  1029. static int
  1030. RDT_DoConnect()
  1031. {
  1032.     if( RDT_connected ) {
  1033.         RDT_Msg("Already connected to %s.\n", RDT_debuggeeName);
  1034.         return 0;
  1035.     }
  1036.     if( RDT_argc > 0 ) {
  1037.         RDT_SetDebuggeeName(RDT_argv[0]);
  1038.         RDT_debuggeePort = 0;
  1039.         if( RDT_argc > 1 ) {
  1040.             int tPort = atoi(RDT_argv[1]);
  1041.             if( tPort >= 0 ) RDT_debuggeePort = ((unsigned)(tPort));
  1042.         }
  1043.     }
  1044.     if( RDT_debuggeeName == NIL ) {
  1045.         RDT_Msg("No debuggee specified.\n");
  1046.         return (0);
  1047.     }
  1048.     RDT_Msg("Connecting to %s ", RDT_debuggeeName);
  1049.     if( RDT_debuggeePort != 0 ) {
  1050.         RDT_Msg("(port %d) ", RDT_debuggeePort);
  1051.     }
  1052.     RDT_Msg("... ");
  1053.     (void) alarm(10);
  1054.     if( RDT_Connect(RDT_debuggeeName, RDT_debuggeePort) != cnrc_ok ) {
  1055.         RDT_Msg("can't connect.\n");
  1056.         (void) alarm(0);
  1057.         return (-1);
  1058.     }
  1059.     RDT_connected = TRUE;
  1060.     (void) alarm(0);
  1061.     return 0;
  1062. }
  1063.  
  1064. static int
  1065. RDT_DoDisconnect(doAbort)
  1066.     int doAbort;
  1067. {
  1068.     (void) RDT_Disconnect(((bool)(doAbort)));
  1069.     RDT_connected = FALSE;
  1070.     return 0;
  1071. }
  1072.  
  1073. void
  1074. RDT_Main (doConnect)
  1075.     bool doConnect;
  1076. {
  1077.     unsigned emptyCommands =    0;
  1078. #   define MAX_EMPTY_COMMANDS    50
  1079.  
  1080.     RDT_InstallHandler(SIGINT, RDT_OnSIGINT);
  1081.     RDT_InstallHandler(SIGALRM, RDT_OnSIGALRM);
  1082.  
  1083.     if( doConnect ) {
  1084.         if( RDT_DoConnect() == 0 ) {
  1085.             RDT_DoWithConnection( RDT_DoGetDebuggeeProtocolVersion,
  1086.                 RDT_PROCS_VERSION );
  1087.         }
  1088.     }
  1089.  
  1090.     for(;;) {
  1091.  
  1092.         switch( RDT_WaitForCmd() ) {
  1093.             case RDT_INCODE_ERR:
  1094.                 if( ++emptyCommands <= MAX_EMPTY_COMMANDS ) continue;
  1095.                 RDT_Msg("RDT_Main emptyCommands error 0\n");
  1096.                 abort();
  1097.                 /*NOTREACHED*/
  1098.             case RDT_INCODE_INT:
  1099.                 RDT_Msg(" ... (interrupted).\n");
  1100.                 continue;
  1101.             case 0:
  1102.                 break;
  1103.             default:
  1104.                 RDT_Msg("RDT_Main botch 0\n");
  1105.                 abort();
  1106.                 /*NOTREACHED*/
  1107.         }
  1108.         if( RDT_cmd == NIL ) {
  1109.         if( ++emptyCommands <= MAX_EMPTY_COMMANDS ) continue;
  1110.         RDT_Msg("RDT_Main emptyCommands error 1\n");
  1111.         abort();
  1112.         /*NOTREACHED*/
  1113.     }
  1114.  
  1115.     emptyCommands = 0;
  1116.     switch( RDT_CmdMatch("stop", 3) ) {
  1117.       case MATCH_HELP:
  1118.         RDT_Msg("sto(p -- stop all processors\n");
  1119.         break;
  1120.       case MATCH_INVOKE:
  1121.         RDT_DoWithConnection( RDT_DoStop, 0 );
  1122.         RDT_Msg("STOP: ");
  1123.         RDT_DoWithConnection( RDT_DoPutThreads, 0 );
  1124.         continue;
  1125.     }
  1126.     switch( RDT_CmdMatch("state", 3) ) {
  1127.       case MATCH_HELP:
  1128.         RDT_Msg("sta(te -- print state\n");
  1129.         break;
  1130.       case MATCH_INVOKE:
  1131.         RDT_DoWithConnection( RDT_DoGetState, 0 );
  1132.         continue;
  1133.     }
  1134.     switch( RDT_CmdMatch("uniprocessor", 3) ) {
  1135.       case MATCH_HELP:
  1136.         RDT_Msg("uni(processor -- run with 1 processor\n");
  1137.         break;
  1138.       case MATCH_INVOKE:
  1139.         RDT_DoWithConnection( RDT_DoSetDBStat, XR_DBSTAT_RUN0 );
  1140.         RDT_examinee = -1;
  1141.         continue;
  1142.     }
  1143.     switch( RDT_CmdMatch("multiprocessor", 5) ) {
  1144.       case MATCH_HELP:
  1145.         RDT_Msg("multi(processor -- run with all processors\n");
  1146.         break;
  1147.       case MATCH_INVOKE:
  1148.         RDT_DoWithConnection( RDT_DoSetDBStat, XR_DBSTAT_RUN );
  1149.         RDT_examinee = -1;
  1150.         continue;
  1151.     }
  1152.     switch( RDT_CmdMatch("examine" /*tid*/, 1) ) {
  1153.       case MATCH_HELP:
  1154.         RDT_Msg( "%s -- %s\n",
  1155.                 "e(xamine threadid", "examine a thread" );
  1156.         break;
  1157.       case MATCH_INVOKE:
  1158.         RDT_DoWithConnection( RDT_DoExamine, 0 );
  1159.         continue;
  1160.     }
  1161.     switch( RDT_CmdMatch("freeze" /*pid*/, 1) ) {
  1162.       case MATCH_HELP:
  1163.         RDT_Msg("f(reeze threadid -- freeze a thread\n");
  1164.         break;
  1165.       case MATCH_INVOKE:
  1166.         RDT_DoWithConnection( RDT_DoFreeze, 0 );
  1167.         continue;
  1168.     }
  1169.     switch( RDT_CmdMatch("kill" /*pid*/, 1) ) {
  1170.       case MATCH_HELP:
  1171.         RDT_Msg("k(ill threadid -- kill thread calling debugger\n");
  1172.         break;
  1173.       case MATCH_INVOKE:
  1174.         RDT_DoWithConnection( RDT_DoKill, 0 );
  1175.         continue;
  1176.     }
  1177.     switch( RDT_CmdMatch("abort", 1) ) {
  1178.       case MATCH_HELP:
  1179.         RDT_Msg("a(bort [(current thread)|*|pid ...] -- abort thread\n");
  1180.         break;
  1181.       case MATCH_INVOKE:
  1182.         RDT_DoWithConnection( RDT_DoAbort, 0 );
  1183.         continue;
  1184.     }
  1185.     switch( RDT_CmdMatch("thaw", 1) ) {
  1186.       case MATCH_HELP:
  1187.         RDT_Msg("t(haw [(current thread)|*|pid ...] -- thaw thread\n");
  1188.         break;
  1189.       case MATCH_INVOKE:
  1190.         RDT_DoWithConnection( RDT_DoThaw, 0 );
  1191.         continue;
  1192.     }
  1193.     switch( RDT_CmdMatch("display", 1) ) {
  1194.       case MATCH_HELP:
  1195.         RDT_Msg("%s -- %s\n",
  1196.                 "d(isplay [threadid [nFrames [verboseLevel]]]",
  1197.                 "display thread stack" );
  1198.         break;
  1199.       case MATCH_INVOKE:
  1200.         RDT_DoWithConnection( RDT_DoDisplayThreads, 0 );
  1201.         continue;
  1202.     }
  1203.  
  1204.     switch( RDT_CmdMatch("peek", 2) ) {
  1205.       case MATCH_HELP:
  1206.         RDT_Msg("%s -- %s\n",
  1207.                 "pe(ek address [nWords]",
  1208.                 "display words of memory" );
  1209.         break;
  1210.       case MATCH_INVOKE:
  1211.         RDT_DoWithConnection( RDT_DoWPeek, 0 );
  1212.         continue;
  1213.     }
  1214.         switch( RDT_CmdMatch("bpeek", 2) ) {
  1215.       case MATCH_HELP:
  1216.         RDT_Msg("%s -- %s\n",
  1217.                 "bp(eek address [nBytes]",
  1218.                 "display bytes of memory" );
  1219.         break;
  1220.       case MATCH_INVOKE:
  1221.         RDT_DoWithConnection( RDT_DoBPeek, 0 );
  1222.         continue;
  1223.     }
  1224.  
  1225.     switch( RDT_CmdMatch("poke", 2) ) {
  1226.       case MATCH_HELP:
  1227.         RDT_Msg("%s -- %s\n",
  1228.                 "po(ke address [word ...]",
  1229.                 "store words of memory" );
  1230.         break;
  1231.       case MATCH_INVOKE:
  1232.         RDT_DoWithConnection( RDT_DoWPoke, 0 );
  1233.         continue;
  1234.     }
  1235.         switch( RDT_CmdMatch("bpoke", 3) ) {
  1236.       case MATCH_HELP:
  1237.         RDT_Msg("%s -- %s\n",
  1238.                 "bpo(ke address [byte ...]",
  1239.                 "store bytes of memory" );
  1240.         break;
  1241.       case MATCH_INVOKE:
  1242.         RDT_DoWithConnection( RDT_DoBPoke, 0 );
  1243.         continue;
  1244.     }
  1245.  
  1246.     switch( RDT_CmdMatch("save", 1) ) {
  1247.       case MATCH_HELP:
  1248.         RDT_Msg( "%s -- %s\n",
  1249.                 "s(ave [threadid]",
  1250.                 "save module names for quick dbx start" );
  1251.         break;
  1252.       case MATCH_INVOKE:
  1253.         RDT_DoWithConnection( RDT_DoSave, 0 );
  1254.         continue;
  1255.     }
  1256.     switch( RDT_CmdMatch("quit", 4 ) ) {
  1257.       case MATCH_HELP:
  1258.         RDT_Msg("quit -- kill XR world\n");
  1259.         break;
  1260.       case MATCH_INVOKE:
  1261.         if( !RDT_connected ) {
  1262.             RDT_Msg("Good-bye.\n");
  1263.             return;
  1264.         }
  1265.             if( RDT_DoKillWorld() != 0 ) {
  1266.                 RDT_Msg("Warning: debuggee not killed.\n");
  1267.             }
  1268.             return;
  1269.     }
  1270.     switch( RDT_CmdMatch("connect", 4 ) ) {
  1271.       case MATCH_HELP:
  1272.         RDT_Msg( "%s -- %s\n",
  1273.                 "connect [host [port]]", "establish connection" );
  1274.         break;
  1275.       case MATCH_INVOKE:
  1276.         if( RDT_DoConnect() == 0 ) {
  1277.             RDT_DoWithConnection( RDT_DoGetDebuggeeProtocolVersion,
  1278.                     RDT_PROCS_VERSION );
  1279.             RDT_Msg("For dbx:\nignore 30 2 11 10\ncont\n\n");
  1280.         }
  1281.         continue;
  1282.     }
  1283.     switch( RDT_CmdMatch("disconnect", 4 ) ) {
  1284.       case MATCH_HELP:
  1285.         RDT_Msg( "%s -- %s\n",
  1286.                 "disconnect", "break connection" );
  1287.         break;
  1288.       case MATCH_INVOKE:
  1289.         (void) RDT_DoDisconnect(TRUE);
  1290.         continue;
  1291.     }
  1292.     switch( RDT_CmdMatch("?", 1 ) ) {
  1293.       case MATCH_HELP:
  1294.         RDT_Msg("? (command) -- print help message\n");
  1295.         continue;
  1296.       case MATCH_INVOKE:
  1297.         continue;
  1298.     }
  1299.  
  1300.     { /* bad command ... */
  1301.         RDT_Msg("Bad command: %s\n", RDT_cmd);
  1302.     }
  1303.  
  1304.  
  1305.     }
  1306.  
  1307. }
  1308.  
  1309.  
  1310. main(argc, argv)
  1311.     int argc;
  1312.     char **argv;
  1313. {
  1314.     bool initialConnectionRequested = FALSE;
  1315.     
  1316.     if( argc > 3 ) {
  1317.         goto Usage;
  1318.     }
  1319.     if( argc > 1 ) {
  1320.         RDT_SetDebuggeeName(argv[1]);
  1321.         if( argc > 2 ) {
  1322.             int tPort = atoi(argv[2]);
  1323.             if( tPort < 0 ) {
  1324.                 RDT_Msg("Bad port: %s\n", argv[2]);
  1325.                 goto Usage;
  1326.             }
  1327.             RDT_debuggeePort = ((unsigned)(tPort));
  1328.         }
  1329.         initialConnectionRequested = TRUE;
  1330.     }
  1331.     RDT_Main(initialConnectionRequested);
  1332.     exit(0);
  1333.  
  1334.   Usage:
  1335.  
  1336.     RDT_Msg("Usage: %s [name [port]]\n", argv[0]);
  1337.     exit(1);
  1338. }
  1339.  
  1340.  
  1341.